package org.exteen.parser;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;

public class Node extends ExprTokensBuilder {

    private List<Object> children = new ArrayList<Object>();
    private StringBuilder text;
    private final Node parent;
    private final String fulltag;
    private final String namespace;
    private final String tag;
    private final Attr[] attributes;

    Node() {
        this(null, null, null, null, new Attr[0]); // root
    }

    Node(Node parent, String namespace, String tag, String fulltag, Attr[] attributes) {
        this.parent = parent;
        this.attributes = attributes;
        this.namespace = "".equals(namespace)?null:namespace;
        this.fulltag = fulltag;
        this.tag = tag;
        if (parent != null) {
            parent.addNode(this);
        }
    }
    
    void append(char c) {
        if (text==null) {
            text = new StringBuilder();
        }
        text.append(c);
    }

    void appendExpression(Expression expr) {
        flushText();
        children.add(expr);
    }

    void addNode(Node builder) {
        flushText();
        children.add(builder);
    }

    Node endElement() {
        flushText();
        return parent;
    }

    private void flushText() {
        if (text != null) {
            String str = text.toString();
            if (str.contains("\"") || str.contains("<") || str.contains(">")) {
                children.add(str);
            } else {
                children.add(new EscapedString(str)); // no ", <, > inside
            }
            text = null;
        }
    }

    public String getNamespace() {
        return namespace;
    }

    public String getTag() {
        return tag;
    }

    public Attr[] getAttributes() {
        return attributes;
    }

    public List<Object> getChildren() {
        return children;
    }

    public String getFullTag() {
        return fulltag;
    }

    public Attr getAttribute(String name) {
        for (Attr a: attributes) {
            if (name.equals(a.getKey())) return a;
        }
        return null;
    }

    public Object getAttributeValue(String name, JexlContext ctx) {
        for (Attr a: attributes) {
            if (name.equals(a.getKey())) {
                return a.getValue(ctx);
            }
        }
        return null;
    }

//    /**
//     * @return optimized Node as string or null if Node contains any variables or custom tags
//     */
//    public String optimizeAndGetAsString() {
//        // children first...
//        int n = children.size();
//        String merged = null;
//        int mergedAt = 0;
//        int removed = 0;
//        for (int i = 0; i<n; i++) {
//            Object obj = children.get(i);
//            String optimized = null;
//            if (obj instanceof String) {
//                optimized = (String) obj;
//            } else if (obj instanceof Node) {
//                optimized = ((Node) obj).optimizeAndGetAsString();
//            }
//            if (optimized == null) {
//                merged = null;
//            } else {
//                if (merged == null) { // first string
//                    merged = optimized;
//                    mergedAt = i;
//                    children.set(mergedAt, merged);
//                } else { // string next to string
//                    merged += optimized;
//                    children.set(i, null);
//                    children.set(mergedAt, merged);
//                    removed++;
//                }
//            }
//        }
//        // remove nulls
//        if (removed>0) {
//            List<Object> newchildren = new ArrayList<Object>(children.size() - removed);
//            for (Object o: children) {
//                if (o!=null) {
//                    newchildren.add(o);
//                }
//            }
//            children = newchildren;
//        }
//        // check if node is able to be optimized
//        if (isNodeOptimizable()) {
//            String optimized = nodeToString();
//            return optimized;
//        }
//        return null;
//    }
//
//    private boolean isNodeOptimizable() {
//        if (namespace==null &&
//                (children.size()==0 || children.size()==1 && (children.get(0) instanceof String))) {
//            if (attributes!=null) {
//                for (Attr a: attributes) {
//                    if (a.isExpression()) {
//                        return false;
//                    }
//                }
//            }
//            return true;
//        }
//        return false;
//    }

//    private String nodeToString() {
//        StringBuilder sb = new StringBuilder();
//        if (attributes == null) {
//            sb.append("<" + getFullTag() + ">");
//        } else {
//            sb.append("<" + getFullTag());
//            for (Attr a : attributes) {
//                Object value = a.getValue(null);
//                System.out.println("Attr value=" + value);
//                sb.append(" " + a.getKey() + "=\"" + EscapedString.escape(value.toString()) + "\"");
//            }
//            sb.append('>');
//        }
//        // body
//        for (Object o: children) {
//            sb.append(o); // assume it is a string
//        }
//        // end
//        sb.append("</" + getFullTag() + ">");
//        return sb.toString();
//    }

    
}
